// Package fixer
// Created by GoLand
// @User: lenora
// @Date: 2024/8/29
// @Time: 10:16

package fixer

import (
	"camp/microbook/pkg/migrator"
	"camp/microbook/pkg/migrator/events"
	"context"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

type Fixer[T migrator.Entity] struct {
	base    *gorm.DB
	target  *gorm.DB
	columns []string
}

func NewFixer[T migrator.Entity](base *gorm.DB, target *gorm.DB) (*Fixer[T], error) {
	row, err := base.Model(new(T)).Order("id").Rows()
	if err != nil {
		return nil, err
	}
	rows, err := row.Columns()
	return &Fixer[T]{base: base, target: target, columns: rows}, err
}

func NewFixerV1[T migrator.Entity](base *gorm.DB, target *gorm.DB, columns []string) *Fixer[T] {
	return &Fixer[T]{base: base, target: target, columns: columns}
}

func (f *Fixer[T]) Fix(ctx context.Context, evt events.Event) error {
	switch evt.Type {
	case events.EventTypeNEQ, events.EventTypeTargetMissing:
		//	数据不一致
		var item T
		err := f.base.WithContext(ctx).
			Where("id = ?", evt.Id).
			First(&item).Error
		switch err {
		case gorm.ErrRecordNotFound:
			return f.target.WithContext(ctx).
				Where("id = ?", evt.Id).
				Delete(&item).Error
		case nil:
			return f.target.WithContext(ctx).
				Clauses(clause.OnConflict{
					DoUpdates: clause.AssignmentColumns(f.columns),
				}).Create(&item).Error
		default:
			return err
		}
	case events.EventTypeBaseMissing:
		//	base表中不存在该数据
		return f.target.WithContext(ctx).
			Where("id = ?", evt.Id).
			Delete(new(T)).Error
	}
	return nil
}

func (f *Fixer[T]) FixV1(ctx context.Context, id uint64) error {
	var item T
	err := f.base.WithContext(ctx).
		Where("id = ?", id).
		First(&item).Error
	switch err {
	case gorm.ErrRecordNotFound:
		return f.target.WithContext(ctx).
			Where("id = ?", id).
			Delete(new(T)).Error
	case nil:
		return f.target.WithContext(ctx).
			Clauses(clause.OnConflict{
				DoUpdates: clause.AssignmentColumns(f.columns),
			}).Create(&item).Error
	default:
		return err
	}
}
